unit SmallStruct.Model.TSSDataModel;

interface

uses
  Classes,
  DB,
  DBClient,
  SmallStruct.Core,
  SmallStruct.Model.TSSModel,
  SmallStruct.Model,
  dialogs,
  SysUtils,
  SmallStruct.Configuration,
  SmallStruct.Configuration.TSSModelConfiguration,
  SmallStruct.Database;

type
  TSSDataModelContext = class(TSSModelContext, ISSDataModelContext)
  private
    _DatabaseConnection: ISSDatabaseDriver;
  public
    procedure SetDatabaseConnection(ADatabaseConnection: ISSDatabaseDriver);
  public
    function GetDatabaseConnection: ISSDatabaseDriver;
  end;

  TSSDataModel = class(TSSModel, ISSDataModel)
  protected
    _OpenCondition: string;
    _DataSource: TDataSource;
    _ClientDataSet: TClientDataSet;
  protected
    function GetDataModelContext: ISSDataModelContext; reintroduce;
    procedure OpenDataSet; virtual; abstract;
    procedure CloseDataSet; virtual; abstract;
    procedure RefreshDataSet; virtual;
    procedure ParseSQL(SQL: TStringList);
    procedure InitDataSet(DataSet: TDataSet);
  public
    function GetDataSet: ISSDataSet; virtual;
    function GetDataSource: TDataSource; virtual;
    function IsAutoOpen: Boolean; virtual;
    function IsReadOnly: Boolean; virtual;
    procedure AppendRecord; virtual;
    procedure ApplyModify; virtual;
    procedure CancelModify; virtual;
    procedure CloseDataModel; virtual;
    procedure DeleteRecord; virtual;
    procedure OpenDataModel(const OpenCondition: string); virtual;
    procedure RefreshDataModel; virtual;
  public
    procedure InitObject; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

uses
  SmallStruct.Database.TSSDataSet;

{ TSSDataModel }

function TSSDataModel.IsAutoOpen: Boolean;
begin
  Result := GetModelConfiguration.IsAutoOpen;
end;

function TSSDataModel.IsReadOnly: Boolean;
begin
  Result := GetModelConfiguration.IsReadOnly;
end;

procedure TSSDataModel.RefreshDataModel;
begin
  RefreshDataSet;
end;

procedure TSSDataModel.OpenDataModel(const OpenCondition: string);
begin
  _OpenCondition := OpenCondition;
  OpenDataSet;
end;

procedure TSSDataModel.ParseSQL(SQL: TStringList);
var
  FieldConfigurations: ISSObjectContainer;
  Index: Integer;
begin
  SQL.Clear;

  FieldConfigurations := GetModelConfiguration.GetFieldConfiguration;

  SQL.Add('SELECT ' + (FieldConfigurations.GetObject(0) as ISSModelFieldConfiguration).GetFieldName);

  for Index := 1 to FieldConfigurations.GetCount - 1 do
    SQL.Add(',' + (FieldConfigurations.GetObject(Index) as ISSModelFieldConfiguration).GetFieldName);

  SQL.Add(' FROM ' + GetModelConfiguration.GetEntityName);

  if Length(GetModelConfiguration.GetOpenCondition) > 0 then
    SQL.Add('WHERE (' + GetModelConfiguration.GetOpenCondition + ')');

  if Length(_OpenCondition) > 0 then
  begin
    if Length(GetModelConfiguration.GetOpenCondition) > 0 then
      SQL.Add(' AND (' + _OpenCondition + ')')
    else
      SQL.Add(' WHERE (' + _OpenCondition + ')');
  end;
end;

function TSSDataModel.GetDataSource: TDataSource;
begin
  Result := _DataSource;
end;

procedure TSSDataModel.CloseDataModel;
begin
  CloseDataSet;
end;

procedure TSSDataModel.InitDataSet(DataSet: TDataSet);
var
  FieldConfigurations: ISSObjectContainer;
  FieldConfiguration: ISSModelFieldConfiguration;
  Index: Integer;
begin
  _ClientDataSet.ReadOnly := GetModelConfiguration.IsReadOnly;

  FieldConfigurations := GetModelConfiguration.GetFieldConfiguration;

  for Index := 0 to FieldConfigurations.GetCount - 1 do
  begin
    FieldConfiguration := FieldConfigurations.GetObject(Index) as ISSModelFieldConfiguration;

    DataSet.FieldByName(FieldConfiguration.GetFieldName).DisplayLabel := FieldConfiguration.GetFieldCaption;
    DataSet.FieldByName(FieldConfiguration.GetFieldName).ProviderFlags := [];
    DataSet.FieldByName(FieldConfiguration.GetFieldName).Required := FieldConfiguration.IsRequired;
    DataSet.FieldByName(FieldConfiguration.GetFieldName).ReadOnly := FieldConfiguration.IsReadOnly;

    if FieldConfiguration.IsPrimaryKey then
      DataSet.FieldByName(FieldConfiguration.GetFieldName).ProviderFlags := [pfInWhere];

    if not FieldConfiguration.IsReadOnly then
      DataSet.FieldByName(FieldConfiguration.GetFieldName).ProviderFlags := DataSet.FieldByName(FieldConfiguration.GetFieldName).ProviderFlags + [pfInUpdate];
  end;
end;

procedure TSSDataModel.InitObject;
begin
  inherited;
  _ClientDataSet.ReadOnly := GetModelConfiguration.IsReadOnly;
end;

function TSSDataModel.GetDataModelContext: ISSDataModelContext;
begin
  Result := GetContext as ISSDataModelContext;
end;

procedure TSSDataModel.CancelModify;
begin
  if _ClientDataSet.Active and not _ClientDataSet.ReadOnly and ((_ClientDataSet.ChangeCount > 0) or _ClientDataSet.Modified) then
    _ClientDataSet.Cancel;
end;

procedure TSSDataModel.ApplyModify;
var
  I: Integer;
  FileName: TStringList;
begin
  if _ClientDataSet.Active and not _ClientDataSet.ReadOnly and ((_ClientDataSet.ChangeCount > 0) or _ClientDataSet.Modified) then
  begin
    _ClientDataSet.ApplyUpdates(0);
  end;
end;

procedure TSSDataModel.DeleteRecord;
begin
  if _ClientDataSet.Active and not _ClientDataSet.ReadOnly and (_ClientDataSet.RecordCount > 0) then
  begin
    _ClientDataSet.Delete;
    _ClientDataSet.ApplyUpdates(0);
  end;
end;

procedure TSSDataModel.AppendRecord;
begin
  if not _ClientDataSet.ReadOnly and _ClientDataSet.Active then
  begin
    _ClientDataSet.Append;
  end;
end;

constructor TSSDataModel.Create(AOwner: TComponent);
begin
  inherited;
  _DataSource := TDataSource.Create(Self);
  _DataSource.Name := '_DataSource';
  _ClientDataSet := TClientDataSet.Create(Self);
  _DataSource.DataSet := _ClientDataSet;
  _ClientDataSet.AutoCalcFields := False;
  _ClientDataSet.ObjectView := False;
end;

destructor TSSDataModel.Destroy;
begin
  _DataSource.Free;
  _ClientDataSet.Free;

  inherited;
end;

function TSSDataModel.GetDataSet: ISSDataSet;
var
  DataSet: TSSDataSet;
begin
  DataSet := TSSDataSet.Create(nil);
  DataSet.InitDataSet(_ClientDataSet);
  Result := DataSet;
end;

procedure TSSDataModel.RefreshDataSet;
var
  Bookmark: TBookmark;
begin
  if _ClientDataSet.Active then
  begin
    _ClientDataSet.DisableControls;
    Bookmark := _ClientDataSet.GetBookmark;
    try
      _ClientDataSet.Cancel;
      _ClientDataSet.Refresh;
      if _ClientDataSet.BookmarkValid(Bookmark) then
        _ClientDataSet.GotoBookmark(Bookmark);
    finally
      _ClientDataSet.FreeBookmark(Bookmark);
      _ClientDataSet.EnableControls;
    end;
  end;
end;

{ TSSDataModelContext }

function TSSDataModelContext.GetDatabaseConnection: ISSDatabaseDriver;
begin
  Result := _DatabaseConnection;
end;

procedure TSSDataModelContext.SetDatabaseConnection(ADatabaseConnection: ISSDatabaseDriver);
begin
  _DatabaseConnection := ADatabaseConnection;
end;

end.
